# -*- coding=utf-8 -*-
"""
作者:None
时间:2024年06月18日
"""
# pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
import requests
from requests.exceptions import Timeout
import random
import string
# pip install pycryptodome -i https://pypi.tuna.tsinghua.edu.cn/simple
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64
import json
import logging
import argparse

logging.basicConfig(format="%(asctime)s %(name)s:%(levelname)s:%(message)s", datefmt="%Y-%m-%d %H:%M:%S",
                    level=logging.INFO)


# 人脸设备控制
class FaceDevice:
    def __init__(self, args) -> None:
        self._args = args
        self._randomdata = None
        self._password = "456258"
        self._authorization = None
        self._userid = None
        self._url = ""
        self._sn = ""
        self._version = ""
        self._global_config = None
        self._session = requests.session()
        self._E03C = True
        self._headers = {
            "Accept": "application/json, text/plain, */*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
            "Connection": "keep-alive",
            "Content-Type": "application/json;charset=UTF-8",
            "Cookie": "lang=zh_CN",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
        }

    def parse_args(self) -> None:
        logging.info(self._args)
        set_config = False
        if self._args.url is None:
            logging.error("请输入门禁设备IP")
            return
        self._url = self._args.url
        self.login()
        self.get_device_info()
        self.get_global_config()

        if self._args.reset is not None:
            self.reset()
            return
        if self._args.showIP is not None:
            self.show_ip(self._args.showIP)
            set_config = True
        if self._args.showDeviceKey is not None:
            self.show_devicekey(self._args.showDeviceKey)
            set_config = True
        if self._args.showPeopleNum is not None:
            self.show_peoplenum(self._args.showPeopleNum)
            set_config = True
        if self._args.identityScore is not None:
            self.set_identify_scores(self._args.identityScore)
            set_config = True
        if self._args.displayContent is not None:
            self.set_custom_displayMode(self._args.displayContent)
            set_config = True
        if set_config:
            self.set_global_config()

        self.logout()

    def get_random(self):
        url = "http://{0}:8090/device/GetRandom".format(self._url)
        data = {
            "lang": "zh_CN",
            "randomlen": 8
        }
        try:
            response = self._session.post(url=url, headers=self._headers, json=data)
            logging.info(
                "/GetRandom 状态码:{0}, 响应内容:{1}".format(response.status_code, response.content.decode("utf-8")))
            if response.status_code == 200:
                result = response.content.decode("utf-8")
                result = json.loads(result)
                self._randomdata = result["data"]["randomdata"]
            else:
                logging.error("/GetRandom failed")
        except Timeout:
            logging.error("{0} 访问超时".format(url))

    def random_string(self, length=8):
        characters = string.ascii_letters + string.digits
        result = ''.join(random.choice(characters) for _ in range(length))
        return result

    def C(self, e):
        """
        encryptPassword
        """
        a = 24
        o = len(e)

        # 将 e 的长度截断为 24 个字符
        e = e[:24]

        # 如果 e 的长度小于 24，用字符 "U" 进行填充
        while a > o:
            e += "U"
            o += 1

        # 输出填充后的密码字符串
        return e

    def y(self, e):
        return ''.join(list(str(self.C(e)))[:16][::-1])

    def Utf8_parse(self, s):
        return bytes(s.encode('utf-8'))

    def encrypt_data(self, data, key, iv):
        cipher = AES.new(key, AES.MODE_CBC, iv)
        padded_data = pad(data, AES.block_size)
        encrypted_data = cipher.encrypt(padded_data)
        return encrypted_data

    def gen_checkcode(self):
        if self._randomdata is None:
            self.get_random()
        e = str(self._randomdata) + self.random_string() + self._password
        o = self.Utf8_parse(self.C(self._password))
        i = self.Utf8_parse(self.y(self._password))
        n = self.Utf8_parse(e)
        data = self.encrypt_data(n, o, i)
        return base64.b64encode(data).decode("utf-8")

    def login(self) -> None:
        url = "http://{0}:8090/device/Login".format(self._url)
        checkcode = self.gen_checkcode()
        data = {
            "checkcode": checkcode,
            "lang": "zh_CN",
            "username": "admin"
        }
        try:
            response = self._session.post(url=url, headers=self._headers, json=data)
            logging.info("/device/Login 状态码:{0}, 响应内容:省略".format(response.status_code))
            if response.status_code == 200:
                result = response.content.decode("utf-8")
                result = json.loads(result)
                self._authorization = result["data"]["authorization"]
                self._userid = result["data"]["userid"]
                logging.info("门禁设备{0}登录".format(self._url))
            else:
                logging.error("/device/Login failed")
        except Timeout:
            logging.error("{0} 访问超时".format(url))

    def logout(self):
        url = "http://{0}:8090/device/Logout".format(self._url)
        data = {
            "authorization": self._authorization,
            "lang": "zh_CN",
            "userid": self._userid
        }

        try:
            response = self._session.post(url=url, headers=self._headers, json=data)
            logging.info("/device/Logout 状态码:{0}, 响应内容:省略".format(response.status_code))
            if response.status_code == 200:
                result = response.content.decode("utf-8")
                result = json.loads(result)
                logging.info("门禁设备{0}退出:{1}".format(self._url, result))
            else:
                logging.error("/device/Logout failed")
        except Timeout:
            logging.error("{0} 访问超时".format(url))

    def get_global_config(self) -> None:
        url = "http://{0}:8090/device/getGlobalConfig".format(self._url)
        data = {
            "authorization": self._authorization,
            "lang": "zh_CN",
            "userid": self._userid
        }

        try:
            response = self._session.post(url=url, headers=self._headers, json=data)
            logging.info("/device/getGlobalConfig 状态码:{0}, 响应内容:省略".format(response.status_code))
            if response.status_code == 200:
                result = response.content.decode("utf-8")
                result = json.loads(result)
                self._global_config = result["data"]
                logging.info("设备sn:{0}".format(self._global_config["ph_device_no"]))
                if self._global_config["ph_device_no"].startswith("E03C"):
                    self._E03C = True
                else:
                    self._E03C = False
                    logging.warn("不支持修改语音识别信息,人脸识别阈值等功能")
            else:
                logging.error("/device/getGlobalConfig failed")
        except Timeout:
            logging.error("{0} 访问超时".format(url))

    def set_custom_displayMode(self, message: str) -> None:
        if not self._E03C:
            logging.warn("不支持修改语音识别信息,人脸识别阈值等功能")
            return

        if self._global_config is not None:
            logging.info("修改 {0} displayModType:{1} -> 100".format(self._url, self._global_config["displayModType"]))
            logging.info(
                "修改 {0} 识别显示文字:{1} -> {2}".format(self._url, self._global_config["displayModContent"], message))
            logging.info("修改 {0} ttsModType:{1}-> 100".format(self._url, self._global_config["ttsModType"]))
            logging.info(
                "修改 {0} 语音播报内容:{1} -> {2}".format(self._url, self._global_config["ttsModContent"], message))
            self._global_config["displayModType"] = 100
            self._global_config["displayModContent"] = message
            self._global_config["ttsModType"] = 100
            self._global_config["ttsModContent"] = message
            self._global_config["authorization"] = self._authorization
            self._global_config["userid"] = self._userid

    def set_identify_scores(self, score: int) -> None:
        """
        人脸识别阈值score: 0-100
        """
        if not self._E03C:
            logging.warn("不支持修改语音识别信息,人脸识别阈值等功能")
            return

        if self._global_config is not None:
            logging.info(
                "修改 {0} 人脸识别阈值:{1} -> {2}".format(self._url, self._global_config["identifyScores"], score))
            self._global_config["identifyScores"] = score
            self._global_config["authorization"] = self._authorization
            self._global_config["userid"] = self._userid

    def show_ip(self, type: int) -> None:
        """
        type: 1---不显示,2---显示
        """
        if not self._E03C:
            logging.warn("不支持修改语音识别信息,人脸识别阈值等功能")
            return

        if type != 1 and type != 2:
            logging.info("type:{0} 值不合法,1---不显示,2---显示".format(type))
            return
        if self._global_config is not None:
            logging.info("修改 {0} 是否显示IP:{1} -> {2}".format(self._url, "显示" if self._global_config[
                                                                                          "showIp"] == 2 else "不显示",
                                                                 "显示" if type == 2 else "不显示"))
            self._global_config["showIp"] = type
            self._global_config["authorization"] = self._authorization
            self._global_config["userid"] = self._userid

    def show_devicekey(self, type: int) -> None:
        """
        type: 1---不显示,2---显示
        """
        if not self._E03C:
            logging.warn("不支持修改语音识别信息,人脸识别阈值等功能")
            return

        if type != 1 and type != 2:
            logging.info("type:{0} 值不合法,1---不显示,2---显示".format(type))
            return
        if self._global_config is not None:
            logging.info("修改 {0} 是否显示devicekey:{1} -> {2}".format(self._url, "显示" if self._global_config[
                                                                                                 "showDeviceKey"] == 2 else "不显示",
                                                                        "显示" if type == 2 else "不显示"))
            self._global_config["showDeviceKey"] = type
            self._global_config["authorization"] = self._authorization
            self._global_config["userid"] = self._userid

    def show_peoplenum(self, type: int) -> None:
        """
        type: 1---不显示,2---显示
        """
        if not self._E03C:
            logging.warn("不支持修改语音识别信息,人脸识别阈值等功能")
            return

        if type != 1 and type != 2:
            logging.info("type:{0} 值不合法,1---不显示,2---显示".format(type))
            return
        if self._global_config is not None:
            logging.info("修改 {0} 是否显示peopleNum:{1} -> {2}".format(self._url, "显示" if self._global_config[
                                                                                                 "showPeopleNum"] == 2 else "不显示",
                                                                        "显示" if type == 2 else "不显示"))
            self._global_config["showPeopleNum"] = type
            self._global_config["authorization"] = self._authorization
            self._global_config["userid"] = self._userid

    def set_identify_distance(self, distance: int) -> None:
        """
        TODO
        """
        pass

    def set_global_config(self) -> None:
        if not self._E03C:
            logging.warn("不支持修改语音识别信息,人脸识别阈值等功能")
            return

        url = "http://{0}:8090/device/setGlobalConfig".format(self._url)
        headers = {
            "Accept": "application/json, text/plain, */*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
            "Connection": "keep-alive",
            "Content-Length": "4529",
            "Content-Type": "application/json;charset=UTF-8",
            "Cookie": "lang=zh_CN",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
        }

        try:
            response = requests.post(url=url, headers=headers, json=self._global_config)
            logging.info("/device/setGlobalConfig 状态码:{0}, 响应内容:{1}".format(response.status_code,
                                                                                   response.content.decode("utf-8")))
            if response.status_code == 200:
                result = response.content.decode("utf-8")
                result = json.loads(result)
                code = result["code"]
                if code == "WEB_EXP-1011":
                    logging.warn(result["msg"] + ",请等待门禁设备升级完成.")
                elif code == "WEB_EXP-1008":
                    logging.error(result["msg"] + ",认证失败.")
                elif code == "WEB_SUS-0":
                    success = result["success"]
                    if success:
                        logging.info("配置修改成功")
            else:
                logging.error("/device/setGlobalConfig failed")
        except Timeout:
            logging.error("{0} 访问超时".format(url))

    def get_device_info(self) -> None:
        url = "http://{0}:8090/device/GetDevInfo".format(self._url)
        headers = {
            "Accept": "application/json, text/plain, */*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
            "Connection": "keep-alive",
            "Content-Length": "35",
            "Content-Type": "application/json;charset=UTF-8",
            "Cookie": "lang=zh_CN",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
        }
        data = {
            "authorization": self._authorization,
            "lang": "zh_CN",
            "userid": self._userid
        }

        try:
            response = self._session.post(url=url, headers=headers, json=data)
            logging.info("/device/GetDevInfo 状态码:{0}, 响应内容:{1}".format(response.status_code,
                                                                              response.content.decode("utf-8")))
            if response.status_code == 200:
                result = response.content.decode("utf-8")
                result = json.loads(result)
                code = result["code"]
                if code == "WEB_EXP-1011":
                    logging.warn(result["msg"] + ",请等待门禁设备升级完成.")
                elif code == "WEB_EXP-1008":
                    logging.error(result["msg"] + ",认证失败.")
                elif code == "WEB_SUS-0":
                    logging.info("当前门禁设备IP:{0}".format(result["data"]["ip"]))
                    logging.info("当前门禁设备SN:{0}".format(result["data"]["SN"]))
                    logging.info("当前门禁设备类型:{0}".format(result["data"]["devtype"]))
                    logging.info("当前门禁设备版本:{0}".format(result["data"]["hardware"]))
                    self._sn = result["data"]["SN"]
                    self._version = result["data"]["hardware"]

                    if self._sn.startswith("E03C"):
                        self._E03C = True
                        logging.info("支持修改语音识别信息,人脸识别阈值等功能")
                    else:
                        self._E03C = False
                        logging.warn("不支持修改语音识别信息,人脸识别阈值等功能")
            else:
                logging.error("/device/GetDevInfo failed")
        except Timeout:
            logging.error("{0} 访问超时".format(url))

    def reset(self) -> None:
        logging.info("正在重置{0}".format(self._url))
        url = "http://{0}:8090/device/Reset".format(self._url)
        headers = {
            "Accept": "application/json, text/plain, */*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
            "Connection": "keep-alive",
            "Content-Length": "35",
            "Content-Type": "application/json;charset=UTF-8",
            "Cookie": "lang=zh_CN",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
        }
        data = {
            "authorization": self._authorization,
            "lang": "zh_CN",
            "userid": self._userid
        }
        response = self._session.post(url=url, headers=headers, json=data, verify=False)
        if response.status_code == 200:
            logging.info("{0}重置成功".format(self._url))
        else:
            logging.error("{0}重置失败".format(self._url))


if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    parser.add_argument("--url", type=str, action="store", help="人脸设备的IP")
    parser.add_argument("--reset", type=int, action="store", help="重置设备")
    parser.add_argument("--showIP", type=int, action="store", help="是否显示人脸设备的IP(1---不显示,2---显示)")
    parser.add_argument("--showDeviceKey", type=int, action="store", help="是否显示人脸设备的SN(1---不显示,2---显示)")
    parser.add_argument("--showPeopleNum", type=int, action="store",
                        help="是否显示人脸设备的存储人数(1---不显示,2---显示)")
    parser.add_argument("--displayContent", type=str, action="store", help="人脸设备识别成功展示的信息")
    parser.add_argument("--identityScore", type=int, action="store", help="人脸设备的识别阈值(0-100)")

    args = parser.parse_args()

    device = FaceDevice(args=args)
    device.parse_args()

